import { CoordinateSystem, GridStyle } from "./Constants";
import GridSystem from "./GridSystem";

let timerOfDraw = 0;

export default class GridLine {

    solidColor: string;
    dashedColor: string;
    zeroColor: string;
    crossLen: number;
    gridStyle: GridStyle;
    width: number;
    height: number;
    background: string;
    lineWidth = .25;
    ctx: CanvasRenderingContext2D;
    glInstance: GridSystem;
    domElement: HTMLCanvasElement;

    constructor(gls: GridSystem, gridStyle = GridStyle.FULLSCREEN, width: number = 200, height: number = 200, background = 'rgba(255,255,255 ,1)') {
        this.glInstance = gls;
        const left = this.glInstance.ctx.canvas.clientLeft;
        const top = this.glInstance.ctx.canvas.clientTop;
        this.domElement = document.createElement("canvas");
        this.domElement.style.position = "fixed";
        this.domElement.style.zIndex = '-1';
        this.domElement.style.left = left + "px";
        this.domElement.style.top = top + "px";
        this.glInstance.domElement.parentNode?.appendChild(this.domElement);
        this.ctx = this.domElement.getContext('2d') || new CanvasRenderingContext2D();
        this.ctx.canvas.width = this.glInstance.ctx.canvas.width;
        this.ctx.canvas.height = this.glInstance.ctx.canvas.height;
        this.solidColor = "rgba(0, 0, 0, .6)"; // 实线颜色
        this.dashedColor = "rgba(0,0,0,.3)"; // 虚线颜色
        this.zeroColor = "rgba(0,0,0,1)"; // 坐标系颜色 #358bf3
        this.crossLen = 1
        this.gridStyle = gridStyle;  // 1 十字架 网格 2 普通网格 3 限制范围网格
        this.width = width;
        this.height = height;
        this.background = background;
        window.onresize = () => {
            this.ctx.canvas.width = this.glInstance.ctx.canvas.width;
            this.ctx.canvas.height = this.glInstance.ctx.canvas.height;
        }
    }

    draw(loop = true) {
        timerOfDraw && cancelAnimationFrame(timerOfDraw)
        this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
        this.drawLine();
        if (loop) {  // 是否循环渲染
            timerOfDraw = window.requestAnimationFrame(() => this.draw(loop))
        }
    };

    drawLine() {
        /*获取绘图工具*/
        // 设置网格大小
        this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
        const gridSize = this.glInstance.getRatioSize(CoordinateSystem.GRID_SIZE);

        // 获取Canvas的width、height
        const CanvasWidth = this.ctx.canvas.width;
        const CanvasHeight = this.ctx.canvas.height;
        // 在 pageSlicePos 的 x，y 点位画一个 10 * 10 的红色标记用来表示当前页面的 0 0 坐标
        const canvasXHeight = CanvasHeight - this.glInstance.pageSlicePos.y;
        const canvasYWidth = CanvasWidth - this.glInstance.pageSlicePos.x;

        const yPageSliceTotal = Math.ceil(canvasYWidth / gridSize); // 计算需要绘画y轴的条数
        const xPageSliceTotal = Math.ceil(canvasXHeight / gridSize);

        // 从 pageSlicePos.y 处开始往 Y 轴负方向画 X 轴网格
        const xRemaining = this.glInstance.pageSlicePos.y;
        const xRemainingTotal = Math.ceil(xRemaining / gridSize);
        // 从 pageSlicePos.x 处开始往 X 轴负方向画 Y 轴网格
        const yRemaining = this.glInstance.pageSlicePos.x;
        const yRemainingTotal = Math.ceil(yRemaining / gridSize);

        this.ctx.save();
        this.ctx.lineWidth = this.lineWidth;
        switch (this.gridStyle) {
            case GridStyle.CROSSLINE:
                const crossLen = this.glInstance.getPixelLen(this.crossLen)
                for (let i = 0; i < xPageSliceTotal; i++) {
                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    for (let j = 0; j < yPageSliceTotal; j++) {
                        this.ctx.moveTo(gridSize * j + this.glInstance.pageSlicePos.x - crossLen, this.glInstance.pageSlicePos.y + gridSize * i);
                        this.ctx.lineTo(gridSize * j + this.glInstance.pageSlicePos.x + crossLen, this.glInstance.pageSlicePos.y + gridSize * i);
                    }
                    for (let j = 0; j < yRemainingTotal; j++) {
                        this.ctx.moveTo(-gridSize * j + this.glInstance.pageSlicePos.x - crossLen, this.glInstance.pageSlicePos.y + gridSize * i);
                        this.ctx.lineTo(-gridSize * j + this.glInstance.pageSlicePos.x + crossLen, this.glInstance.pageSlicePos.y + gridSize * i);
                    }
                    this.ctx.strokeStyle = "#c2c2d6"; // 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
                    this.ctx.stroke();
                }

                for (let j = 0; j < yPageSliceTotal; j++) {
                    this.ctx.beginPath(); // 开启路径，设置不同的样式  
                    for (let i = 0; i < xPageSliceTotal; i++) {
                        this.ctx.moveTo(this.glInstance.pageSlicePos.x + gridSize * j, this.glInstance.pageSlicePos.y + gridSize * i - crossLen);
                        this.ctx.lineTo(this.glInstance.pageSlicePos.x + gridSize * j, this.glInstance.pageSlicePos.y + gridSize * i + crossLen);
                    }
                    for (let i = 0; i < xRemainingTotal; i++) {
                        this.ctx.moveTo(this.glInstance.pageSlicePos.x + gridSize * j, this.glInstance.pageSlicePos.y - gridSize * i - crossLen);
                        this.ctx.lineTo(this.glInstance.pageSlicePos.x + gridSize * j, this.glInstance.pageSlicePos.y - gridSize * i + crossLen);
                    }
                    this.ctx.strokeStyle = "#c2c2d6";// 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
                    this.ctx.stroke();
                }

                for (let j = 0; j < yRemainingTotal; j++) {
                    if (j === 0) continue;
                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    for (let i = 0; i < xPageSliceTotal; i++) {
                        this.ctx.moveTo(this.glInstance.pageSlicePos.x - gridSize * j, this.glInstance.pageSlicePos.y + gridSize * i - crossLen);
                        this.ctx.lineTo(this.glInstance.pageSlicePos.x - gridSize * j, this.glInstance.pageSlicePos.y + gridSize * i + crossLen);
                    }
                    for (let i = 0; i < xRemainingTotal; i++) {
                        this.ctx.moveTo(this.glInstance.pageSlicePos.x - gridSize * j, this.glInstance.pageSlicePos.y - gridSize * i - crossLen);
                        this.ctx.lineTo(this.glInstance.pageSlicePos.x - gridSize * j, this.glInstance.pageSlicePos.y - gridSize * i + crossLen);
                    }
                    this.ctx.strokeStyle = "#c2c2d6";// 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
                    this.ctx.stroke();
                }


                for (let i = 0; i < xRemainingTotal; i++) {
                    if (i === 0) continue;
                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    for (let j = 0; j < yPageSliceTotal; j++) {
                        this.ctx.moveTo(gridSize * j + this.glInstance.pageSlicePos.x - crossLen, this.glInstance.pageSlicePos.y - gridSize * i);
                        this.ctx.lineTo(gridSize * j + this.glInstance.pageSlicePos.x + crossLen, this.glInstance.pageSlicePos.y - gridSize * i);
                    }
                    for (let j = 0; j < yRemainingTotal; j++) {
                        this.ctx.moveTo(-gridSize * j + this.glInstance.pageSlicePos.x - crossLen, this.glInstance.pageSlicePos.y - gridSize * i);
                        this.ctx.lineTo(-gridSize * j + this.glInstance.pageSlicePos.x + crossLen, this.glInstance.pageSlicePos.y - gridSize * i);
                    }
                    this.ctx.strokeStyle = "#c2c2d6";// 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
                    this.ctx.stroke();
                }

                break;
            case GridStyle.FULLSCREEN:
                // 从 pageSlicePos.y 处开始往 Y 轴正方向画 X 轴网格
                for (let i = 0; i < xPageSliceTotal; i++) {
                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    this.ctx.moveTo(0, this.glInstance.pageSlicePos.y + gridSize * i);
                    this.ctx.lineTo(CanvasWidth, this.glInstance.pageSlicePos.y + gridSize * i);
                    this.ctx.strokeStyle = i === 0 ? this.zeroColor : (i % 5 === 0 ? this.solidColor : this.dashedColor); // 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
                    this.ctx.stroke();
                }

                // 从 pageSlicePos.y 处开始往 Y 轴负方向画 X 轴网格
                for (let i = 0; i < xRemainingTotal; i++) {
                    if (i === 0) continue;
                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    this.ctx.moveTo(0, this.glInstance.pageSlicePos.y - gridSize * i); // -0.5是为了解决像素模糊问题
                    this.ctx.lineTo(CanvasWidth, this.glInstance.pageSlicePos.y - gridSize * i);
                    this.ctx.strokeStyle = i === 0 ? this.zeroColor : (i % 5 === 0 ? this.solidColor : this.dashedColor);// 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
                    this.ctx.stroke();
                }

                // 从 pageSlicePos.x 处开始往 X 轴正方向画 Y 轴网格
                for (let j = 0; j < yPageSliceTotal; j++) {
                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    this.ctx.moveTo(this.glInstance.pageSlicePos.x + gridSize * j, 0);
                    this.ctx.lineTo(this.glInstance.pageSlicePos.x + gridSize * j, CanvasHeight);
                    this.ctx.strokeStyle = j === 0 ? this.zeroColor : (j % 5 === 0 ? this.solidColor : this.dashedColor);// 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
                    this.ctx.stroke();
                }

                // 从 pageSlicePos.x 处开始往 X 轴负方向画 Y 轴网格
                for (let j = 0; j < yRemainingTotal; j++) {
                    if (j === 0) continue;
                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    this.ctx.moveTo(this.glInstance.pageSlicePos.x - gridSize * j, 0);
                    this.ctx.lineTo(this.glInstance.pageSlicePos.x - gridSize * j, CanvasHeight);
                    this.ctx.strokeStyle = j === 0 ? this.zeroColor : (j % 5 === 0 ? this.solidColor : this.dashedColor);// 如果为 0 则用蓝色标记，取余 5 为实线，其余为比较淡的线
                    this.ctx.stroke();
                }
                break;
            case GridStyle.RANGE:
                const width = this.glInstance.getRatioSize(this.width);
                const height = this.glInstance.getRatioSize(this.height);
                const ySliceTotal = Math.ceil(width / gridSize); // 计算需要绘画y轴的条数
                const xSliceTotal = Math.ceil(height / gridSize);
                this.ctx.fillStyle = this.background
                this.ctx.fillRect(this.glInstance.pageSlicePos.x - width, this.glInstance.pageSlicePos.y - height, width * 2, height * 2);

                for (let i = 0; i < xSliceTotal; i++) {
                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    this.ctx.moveTo(this.glInstance.pageSlicePos.x - width, this.glInstance.pageSlicePos.y - gridSize * i)
                    this.ctx.lineTo(this.glInstance.pageSlicePos.x + width, this.glInstance.pageSlicePos.y - gridSize * i)
                    this.ctx.strokeStyle = this.solidColor
                    this.ctx.stroke()

                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    this.ctx.moveTo(this.glInstance.pageSlicePos.x - width, this.glInstance.pageSlicePos.y + gridSize * i)
                    this.ctx.lineTo(this.glInstance.pageSlicePos.x + width, this.glInstance.pageSlicePos.y + gridSize * i)
                    this.ctx.strokeStyle = this.solidColor
                    this.ctx.stroke()
                }

                for (let i = 0; i < ySliceTotal; i++) {
                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    this.ctx.moveTo(this.glInstance.pageSlicePos.x - gridSize * i, this.glInstance.pageSlicePos.y - height)
                    this.ctx.lineTo(this.glInstance.pageSlicePos.x - gridSize * i, this.glInstance.pageSlicePos.y + height)
                    this.ctx.strokeStyle = this.solidColor
                    this.ctx.stroke()

                    this.ctx.beginPath(); // 开启路径，设置不同的样式
                    this.ctx.moveTo(this.glInstance.pageSlicePos.x + gridSize * i, this.glInstance.pageSlicePos.y - height)
                    this.ctx.lineTo(this.glInstance.pageSlicePos.x + gridSize * i, this.glInstance.pageSlicePos.y + height)
                    this.ctx.strokeStyle = this.solidColor
                    this.ctx.stroke()
                }
                break;
            default:
                break;
        }
        this.ctx.fillStyle = 'red';
        this.ctx.fillRect(this.glInstance.pageSlicePos.x - 5, this.glInstance.pageSlicePos.y - 5, 10, 10); // 效果图红色小方块
        this.ctx.restore();
    }

    destroy() {
        cancelAnimationFrame(timerOfDraw);
        const parentNode = this.glInstance.domElement.parentNode as HTMLElement;
        parentNode.removeChild(this.domElement)
    }
}